# coding=utf8
import sys
import time
import socket
import struct
from collections import namedtuple


class SourceStatus:
    
    IDLE = 1
    ACTIVE =2
    RECHARGE =3
    
    @classmethod
    def get_status_string(cls, status):
        for status_name in  cls.__dict__:
            if cls.__dict__[status_name]==status:
                return status_name
        
  
class SourceForTest2(object):

    def __init__(self, address, port, source_name, delay, source_status=SourceStatus.IDLE, fields ={} ):
        self.address = address
        self.port = port
        self.source_name = source_name
        self.source_status = source_status
        self.fields = fields
        self.delay = delay

    def start(self):
        self.running = True
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((self.address, self.port))                
        message_number = 1
        while self.running:
            message = bytearray()
            time.sleep(self.delay)
            header =  bytearray(b'\x01')
            msg_num = struct.pack('!H', message_number)
            
            '''
            если длина недостаточна, добавить пробелов(слева), 8 * ' ' вместо 7 * ' ' - чтобы было легко обнаружить, что в source_name передали пустую строку
            (иначе сообщение будет иметь неверный формат)
            Слишком длинное source_name укорачивается справа)
            '''
            source_name = (8*' '+self.source_name[:8])[-8:]
            
            source_name = source_name.encode('ascii')
            status = struct.pack('!B', self.source_status)
            nf = struct.pack('!B', len(self.fields))
            fields_data = bytearray()
           
            for f_name in self.fields:
                fields_data+=(8*' '+f_name[:8])[-8:].encode('ascii')
                fields_data+=struct.pack('!i', self.fields[f_name])

            #пример сообщения
            #_message = bytearray(b'\x01\x00\x01\x20\x20\x20\x20\x20\x65\x66\x67\x01\x01\x20\x20\x20\x20\x20\x65\x65\x65\x00\x00\x00\x03')
           
           
            message = message.join([header, msg_num, source_name, status, nf, fields_data])
            #считаем побайтовый XOR
            message.append(reduce(lambda x,y: x^y, message))

            message_number+=1
            
            #при желании можно изобразить поврежденное сообщение
            #message[-1] = 0x01

            s.send(message)

            data = s.recv(1024)

            if self.is_message_valid(bytearray(data)):
                print('Message %i successfully processed by server' % struct.unpack('!H', data[1:3])[0])
            else:
                print('Error! Server reports invalid message!')


        s.close()


    def is_message_valid(self, message_bytes):
        return message_bytes[0]==0x11 and \
               message_bytes[-1] == reduce(lambda x,y: x^y, message_bytes[:-1])  


'''
Запускать с 2 параметрами - имя источника и интервал отправки сообщений
'''
        
if __name__ == '__main__':
    
    
    if len(sys.argv)!=3:
        print('2 arguments(source_name and delay) required')
        sys.exit()

    source = SourceForTest2('127.0.0.1', 8888, source_name = sys.argv[1], delay=float(sys.argv[2]), fields={'fields':111,
                                                                                                      'endless':10,
                                                                                                      'fields...':1

                                                                                                      })
    source.start()
    
   